/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.gephi.statistics.spi;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.gephi.statistics.spi.path.LAF;
import org.gephi.statistics.spi.path.LGraph;
import org.python.util.PythonInterpreter;

import u.can.i.up.category.FactorUtils;
import u.can.i.up.db.postgresql.Aliases;
import u.can.i.up.db.postgresql.TotalDownloads;

/**
 *
 * @author lczgywzyy
 */
public class CRSMetrics {

	Logger logger = LogManager.getLogger();

	private final static CRSMetrics instance = new CRSMetrics();

	public static CRSMetrics getInstance() {
		return instance;
	}

	private final Properties props = System.getProperties();
	private final String separator = props.getProperty("file.separator");// .toLowerCase().startsWith("win"))?
																			// "\\":"/";
	// private final String tmpDir = props.getProperty("java.io.tmpdir");
	private final String userHome = props.getProperty("user.home");
	private final String userDir = props.getProperty("user.dir");
	private final String sysBit = props.getProperty("sun.arch.data.model");
	private final String osName = props.getProperty("os.name").toLowerCase();

	private final String Term_Info = userHome + separator + ".csmetrics" + separator + "term_info.txt";
	private final String Termid_List = userHome + separator + ".csmetrics" + separator + "termid_list.txt";
	private final String Co_Matrix = userHome + separator + ".csmetrics" + separator + "co_mat.txt";
	private final String Waf_Matrix = userHome + separator + ".csmetrics" + separator + "waf_mat.txt";
	private final String Affinity_Matrix = userHome + separator + ".csmetrics" + separator + "affinity_mat.txt";

	Map<Integer, ArrayList<Integer>> outerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();
	Map<Integer, ArrayList<Integer>> innerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();

	static {
		if (instance.osName.startsWith("win")) {
			System.load(instance.userDir + instance.separator + "jniLibs" + instance.separator + "libwaf" + instance.sysBit + ".dll");
		} else if (instance.osName.startsWith("lin")) {
			System.load(instance.userDir + instance.separator + "jniLibs" + instance.separator + "libwaf" + instance.sysBit + ".so");
		} else if (instance.osName.startsWith("mac")) {
			System.load(instance.userDir + instance.separator + "jniLibs" + instance.separator + "libwaf" + instance.sysBit + ".jnilib");
		}
		// System.loadLibrary("waf");
	}

	public native int intMethod(int num);

	/**
	 * input: Term_Info, Termid_List; output: Co_Matrix
	 */
	public native int calculateCoMatrix(String mTermInfo, String mTermidList, String mCoMatrix, String mWinSize);

	/**
	 * input: Term_Info, Co_Matrix; output: Waf_Matrix
	 */
	public native int calculateWafMatrix(String mCoMatrix, String mTermInfo, String mWafMatrix, String mParam);

	/**
	 * input: Term_Info, Co_Matrix; output: Waf_Matrix
	 */
	public native int calculateAffinityMatrix(String mWafMatrix, String mTermInfo, String mAffinityMatrix,
			String mParam);

	/**
	 * input: Termid_List; output: Term_info
	 */
	public native int calculateTermInfo(String mTermidList, String mTermInfo);

	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValuesNaive(String mWafMatrix) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int key = Integer.parseInt(line.split("->")[0].trim());
					float value = 0.0f;
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains(":") && tmpStr.contains(")")) {
						value += Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
					// logger.info("" + key + ":" + value);
					returnMap.put(key, value);
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			float value = (float) entry.getValue();
			logger.info("" + key + ":" + value);
		}
		return returnMap;
	}

	public void fetchSourceNode(List<Aliases> aliases, HashSet<Integer> allNodeIDSet, HashSet<Integer> startNodeIDSet,
			HashSet<Integer> endNodeIDSet) {
		HashSet<Integer> sourceNodeIDSet = new HashSet<Integer>();
		HashSet<Integer> targetNodeIDSet = new HashSet<Integer>();
		for (int i = 0; i < aliases.size(); i++) {
			sourceNodeIDSet.add(aliases.get(i).getSid());
			targetNodeIDSet.add(aliases.get(i).getTid());
			allNodeIDSet.add(aliases.get(i).getSid());
			allNodeIDSet.add(aliases.get(i).getTid());
		}
		startNodeIDSet.addAll(allNodeIDSet);
		endNodeIDSet.addAll(allNodeIDSet);
		for (int i : targetNodeIDSet) {
			startNodeIDSet.remove(i);
		}
		for (int i : sourceNodeIDSet) {
			endNodeIDSet.remove(i);
		}
	}

	@SuppressWarnings("rawtypes")
	public void writeTerm_infor(List<Aliases> aliases, String filePath, HashMap<Integer, Integer> downloadMap,
			HashMap<Integer, Integer> categoryMap) {
		BufferedWriter bufWriter = null;
		try {
			File f = new File(filePath).getParentFile();
			if (!f.exists()) {
				f.mkdirs();
			}
			bufWriter = new BufferedWriter(new FileWriter(filePath));
			Map<String, Integer> termid_map = new HashMap<String, Integer>();
			for (int i = 0; i < aliases.size(); i++) {
				Aliases a = aliases.get(i);
				String keyS = "" + a.getSid() + "\t" + a.getScomponent();
				String keyT = "" + a.getTid() + "\t" + a.getTcomponent();
				termid_map.put(keyS, (termid_map.get(keyS) == null) ? 1 : (termid_map.get(keyS) + 1));
				termid_map.put(keyT, (termid_map.get(keyT) == null) ? 1 : (termid_map.get(keyT) + 1));
				downloadMap.put(a.getSid(), a.getSdownload());
				categoryMap.put(a.getSid(), a.getScategoryid());
				downloadMap.put(a.getTid(), a.getTdownload());
				categoryMap.put(a.getTid(), a.getTcategoryid());
			}
			bufWriter.write("termid_size=" + termid_map.size() + "\n");
			bufWriter.write("<term_freq>	<termid>	<term>" + "\n");
			Iterator iter = termid_map.entrySet().iterator();
			while (iter.hasNext()) {
				Map.Entry entry = (Map.Entry) iter.next();
				String key = (String) entry.getKey();
				int val = (int) entry.getValue();
				bufWriter.write(val + "\t" + key + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void writeAliases(List<Aliases> aliases, String filePath) {
		BufferedWriter bufWriter = null;
		try {
			bufWriter = new BufferedWriter(new FileWriter(filePath));
			for (int i = 0; i < aliases.size(); i++) {
				Aliases a = aliases.get(i);
				String keyS = "" + a.getSid();
				String keyT = "" + a.getTid();
				bufWriter.write(keyS + " " + keyT + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * @author lczgywzyy
	 * @param mWafMatrix
	 *            waf文件路径；
	 * @param downloadMap
	 *            应用下载量；
	 * @param totalDownloads
	 *            总下载量；
	 * @param categoryMap
	 *            应用类别；
	 * @param factorMatrix
	 *            类别因子矩阵；
	 * @param scale_size
	 *            聚合节点规模，过滤聚合节点小于该值的连通图；
	 * @param tag
	 *            分支标签。
	 * @return WafValues值Map。
	 */
	public Map<Integer, Float> calculateWafValues(String mWafMatrix, HashMap<Integer, Integer> downloadMap,
			TotalDownloads totalDownloads, HashMap<Integer, Integer> categoryMap, FactorUtils categoryFactorMatrix,
			int scale_size, int tag) {
		switch (tag) {
		case 1:
			return calculateWafValues1(mWafMatrix);
		case 2:
			return calculateWafValues2(mWafMatrix);
		case 3:
			return calculateWafValues3(mWafMatrix);
		case 4:
			return calculateWafValues4(mWafMatrix, downloadMap, totalDownloads, scale_size);
		case 5:
			return calculateWafValues5(mWafMatrix, downloadMap, totalDownloads, categoryMap, categoryFactorMatrix,
					scale_size);
		default:
			return null;
		}

	}

	/**
	 * NOR(inner, outer) = min(inner, outer) / max(inner, outer).
	 */
	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValues1(String mWafMatrix) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		Map<Integer, ArrayList<Float>> outerMap = new HashMap<Integer, ArrayList<Float>>();
		Map<Integer, ArrayList<Float>> innerMap = new HashMap<Integer, ArrayList<Float>>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int outerKey = Integer.parseInt(line.split("->")[0].trim());
					if (outerMap.get(outerKey) == null || outerMap.get(outerKey).isEmpty()) {
						ArrayList<Float> tmplist = new ArrayList<Float>();
						outerMap.put(outerKey, tmplist);
					}
					if (returnMap.get(outerKey) == null) {
						Float tmp = 0.0f;
						returnMap.put(outerKey, tmp);
					}
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains("(") && tmpStr.contains(":") && tmpStr.contains(")")) {
						int innerKey = Integer
								.parseInt(tmpStr.substring(tmpStr.indexOf("(") + 1, tmpStr.indexOf(":")).trim());
						if (innerMap.get(innerKey) == null || innerMap.get(innerKey).isEmpty()) {
							ArrayList<Float> tmplist = new ArrayList<Float>();
							innerMap.put(innerKey, tmplist);
						}
						if (returnMap.get(innerKey) == null) {
							Float tmp = 0.0f;
							returnMap.put(innerKey, tmp);
						}
						float value = Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						outerMap.get(outerKey).add(value);
						innerMap.get(innerKey).add(value);
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			ArrayList<Float> outerValueList = outerMap.get(key);
			float outerValue = 0.0f;
			int outerValueSize = 0;
			if (outerValueList != null && !outerValueList.isEmpty()) {
				for (float v : outerValueList) {
					outerValue += v;
				}
				outerValueSize = outerValueList.size();
			}
			ArrayList<Float> innerValueList = innerMap.get(key);
			float innerValue = 0.0f;
			int innerValueSize = 0;
			if (innerValueList != null && !innerValueList.isEmpty()) {
				for (float v : innerValueList) {
					innerValue += v;
				}
				innerValueSize = innerValueList.size();
			}

			float outerValeAverage = (outerValueSize != 0) ? (outerValue) : 0;
			float innerValeAverage = (innerValueSize != 0) ? (innerValue) : 0;

			returnMap.put(key, NOR(outerValeAverage, innerValeAverage));
		}
		return returnMap;
	}

	/**
	 * NOR(Average(inner), Average(outer)) = min(Average(inner), Average(outer))
	 * / max(Average(inner), Average(outer)).
	 */
	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValues2(String mWafMatrix) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		Map<Integer, ArrayList<Float>> outerMap = new HashMap<Integer, ArrayList<Float>>();
		Map<Integer, ArrayList<Float>> innerMap = new HashMap<Integer, ArrayList<Float>>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int outerKey = Integer.parseInt(line.split("->")[0].trim());
					if (outerMap.get(outerKey) == null || outerMap.get(outerKey).isEmpty()) {
						ArrayList<Float> tmplist = new ArrayList<Float>();
						outerMap.put(outerKey, tmplist);
					}
					if (returnMap.get(outerKey) == null) {
						Float tmp = 0.0f;
						returnMap.put(outerKey, tmp);
					}
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains("(") && tmpStr.contains(":") && tmpStr.contains(")")) {
						int innerKey = Integer
								.parseInt(tmpStr.substring(tmpStr.indexOf("(") + 1, tmpStr.indexOf(":")).trim());
						if (innerMap.get(innerKey) == null || innerMap.get(innerKey).isEmpty()) {
							ArrayList<Float> tmplist = new ArrayList<Float>();
							innerMap.put(innerKey, tmplist);
						}
						if (returnMap.get(innerKey) == null) {
							Float tmp = 0.0f;
							returnMap.put(innerKey, tmp);
						}
						float value = Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						outerMap.get(outerKey).add(value);
						innerMap.get(innerKey).add(value);
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			ArrayList<Float> outerValueList = outerMap.get(key);
			float outerValue = 0.0f;
			int outerValueSize = 0;
			if (outerValueList != null && !outerValueList.isEmpty()) {
				for (float v : outerValueList) {
					outerValue += v;
				}
				outerValueSize = outerValueList.size();
			}
			ArrayList<Float> innerValueList = innerMap.get(key);
			float innerValue = 0.0f;
			int innerValueSize = 0;
			if (innerValueList != null && !innerValueList.isEmpty()) {
				for (float v : innerValueList) {
					innerValue += v;
				}
				innerValueSize = innerValueList.size();
			}

			float outerValeAverage = (outerValueSize != 0) ? (outerValue / outerValueSize) : 0;
			float innerValeAverage = (innerValueSize != 0) ? (innerValue / innerValueSize) : 0;

			returnMap.put(key, NOR(outerValeAverage, innerValeAverage));
		}
		return returnMap;
	}

	/**
	 * NOR(Average(SUM(NOR(inner_i, inner_j))), Average(SUM(NOR(outer_i,
	 * outer_j))))
	 */
	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValues3(String mWafMatrix) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		Map<Integer, ArrayList<Float>> outerMap = new HashMap<Integer, ArrayList<Float>>();
		Map<Integer, ArrayList<Float>> innerMap = new HashMap<Integer, ArrayList<Float>>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int outerKey = Integer.parseInt(line.split("->")[0].trim());
					if (outerMap.get(outerKey) == null || outerMap.get(outerKey).isEmpty()) {
						ArrayList<Float> tmplist = new ArrayList<Float>();
						outerMap.put(outerKey, tmplist);
					}
					if (returnMap.get(outerKey) == null) {
						Float tmp = 0.0f;
						returnMap.put(outerKey, tmp);
					}
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains("(") && tmpStr.contains(":") && tmpStr.contains(")")) {
						int innerKey = Integer
								.parseInt(tmpStr.substring(tmpStr.indexOf("(") + 1, tmpStr.indexOf(":")).trim());
						if (innerMap.get(innerKey) == null || innerMap.get(innerKey).isEmpty()) {
							ArrayList<Float> tmplist = new ArrayList<Float>();
							innerMap.put(innerKey, tmplist);
						}
						if (returnMap.get(innerKey) == null) {
							Float tmp = 0.0f;
							returnMap.put(innerKey, tmp);
						}
						float value = Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						outerMap.get(outerKey).add(value);
						innerMap.get(innerKey).add(value);
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			ArrayList<Float> outerValueList = outerMap.get(key);
			float outerValue = 0.0f;
			int outerValueSize = 0;
			if (outerValueList != null && !outerValueList.isEmpty()) {
				if (outerValueList.size() == 1) {
					// outerValue += outerValueList.get(0);
					outerValue += 0;
				} else {
					for (int i = 0; i < outerValueList.size(); i++) {
						float u = outerValueList.get(i);
						for (int j = i + 1; j < outerValueList.size(); j++) {
							float v = outerValueList.get(j);
							outerValue += NOR(u, v);
						}
					}
				}
				outerValueSize = outerValueList.size();
			}
			ArrayList<Float> innerValueList = innerMap.get(key);
			float innerValue = 0.0f;
			int innerValueSize = 0;
			if (innerValueList != null && !innerValueList.isEmpty()) {
				if (innerValueList.size() == 1) {
					// innerValue += innerValueList.get(0);
					innerValue += 0;
				} else {
					for (int i = 0; i < innerValueList.size(); i++) {
						float u = innerValueList.get(i);
						for (int j = i + 1; j < innerValueList.size(); j++) {
							float v = innerValueList.get(j);
							innerValue += NOR(u, v);
						}
					}
				}
				innerValueSize = innerValueList.size();
			}

			float outerValeAverage = (outerValueSize != 0) ? (outerValue / outerValueSize) : 0;
			float innerValeAverage = (innerValueSize != 0) ? (innerValue / innerValueSize) : 0;

			returnMap.put(key, NOR(outerValeAverage, innerValeAverage));
		}
		return returnMap;
	}

	/**
	 * @author lczgywzyy
	 * @param mWafMatrix
	 *            waf文件路径；
	 * @param downloadMap
	 *            应用下载量；
	 * @param totalDownloads
	 *            总下载量；
	 * @param scale_size
	 *            聚合节点规模；
	 * @param tag
	 *            分支标签。
	 * 
	 * @since NOR(Average(SUM(NOR(inner_i * factor_i, inner_j * factor_j))),
	 *        Average(SUM(NOR(outer_i * factor_i, outer_j * factor_j))))
	 */
	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValues4(String mWafMatrix, HashMap<Integer, Integer> downloadMap,
			TotalDownloads totalDownloads, int scale_size) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		Map<Integer, Map<Integer, Float>> outerMap = new HashMap<Integer, Map<Integer, Float>>();
		Map<Integer, Map<Integer, Float>> innerMap = new HashMap<Integer, Map<Integer, Float>>();
		Map<Integer, ArrayList<Integer>> outerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();
		Map<Integer, ArrayList<Integer>> innerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int outerKey = Integer.parseInt(line.split("->")[0].trim());
					if (outerMap.get(outerKey) == null || outerMap.get(outerKey).isEmpty()) {
						// ArrayList<Float> tmplist = new ArrayList<Float>();
						// Map<Integer, Float> tmpMap = new HashMap<Integer,
						// Float>();
						outerMap.put(outerKey, new HashMap<Integer, Float>());
						outerValueKeyMap.put(outerKey, new ArrayList<Integer>());
					}
					if (returnMap.get(outerKey) == null) {
						Float tmp = 0.0f;
						returnMap.put(outerKey, tmp);
					}
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains("(") && tmpStr.contains(":") && tmpStr.contains(")")) {
						int innerKey = Integer
								.parseInt(tmpStr.substring(tmpStr.indexOf("(") + 1, tmpStr.indexOf(":")).trim());
						if (innerMap.get(innerKey) == null || innerMap.get(innerKey).isEmpty()) {
							// ArrayList<Float> tmplist = new
							// ArrayList<Float>();
							// Map<Integer, Float> tmpMap = new HashMap<Integer,
							// Float>();
							innerMap.put(innerKey, new HashMap<Integer, Float>());
							innerValueKeyMap.put(innerKey, new ArrayList<Integer>());
						}
						if (returnMap.get(innerKey) == null) {
							Float tmp = 0.0f;
							returnMap.put(innerKey, tmp);
						}
						float value = Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						// outerMap.get(outerKey).add(value);
						// innerMap.get(innerKey).add(value);
						outerMap.get(outerKey).put(innerKey, value);
						outerValueKeyMap.get(outerKey).add(innerKey);
						innerMap.get(innerKey).put(outerKey, value);
						innerValueKeyMap.get(innerKey).add(outerKey);
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			// ArrayList<Float> outerValueList = outerMap.get(key);
			Map<Integer, Float> outerValueMap = outerMap.get(key);
			ArrayList<Integer> outerKeyList = outerValueKeyMap.get(key);
			float outerValue = 0.0f;
			int outerValueSize = 0;
			if (outerValueMap != null && !outerValueMap.isEmpty()) {
				if (outerValueMap.size() == 1) {
					float factor_i = calculateDownloadNumbersFacor(
							(downloadMap.get(key) != null) ? downloadMap.get(key) : 0, totalDownloads.getCounts());
					float factor_j = calculateDownloadNumbersFacor(
							(downloadMap.get(outerKeyList.get(0)) != null) ? downloadMap.get(outerKeyList.get(0)) : 0,
							totalDownloads.getCounts());
					outerValue += outerValueMap.get(outerKeyList.get(0)) * factor_i * factor_j;
					// outerValue += 0;
				} else {
					for (int i = 0; i < outerKeyList.size(); i++) {
						int key_i = outerKeyList.get(i);
						float u = outerValueMap.get(key_i);
						float factor_u = calculateDownloadNumbersFacor(
								(downloadMap.get(key_i) != null) ? downloadMap.get(key_i) : 0,
								totalDownloads.getCounts());
						for (int j = i + 1; j < outerKeyList.size(); j++) {
							int key_j = outerKeyList.get(j);
							float v = outerValueMap.get(key_j);
							float factor_v = calculateDownloadNumbersFacor(
									(downloadMap.get(key_j) != null) ? downloadMap.get(key_j) : 0,
									totalDownloads.getCounts());
							outerValue += NOR(u * factor_u, v * factor_v);
						}
					}
				}
				outerValueSize = outerValueMap.size();
			}
			// ArrayList<Float> innerValueList = innerMap.get(key);
			Map<Integer, Float> innerValueMap = innerMap.get(key);
			ArrayList<Integer> innerKeyList = innerValueKeyMap.get(key);
			float innerValue = 0.0f;
			int innerValueSize = 0;
			if (innerValueMap != null && !innerValueMap.isEmpty()) {
				if (innerValueMap.size() == 1) {
					float factor_i = calculateDownloadNumbersFacor(
							(downloadMap.get(innerKeyList.get(0)) != null) ? downloadMap.get(innerKeyList.get(0)) : 0,
							totalDownloads.getCounts());
					float factor_j = calculateDownloadNumbersFacor(
							(downloadMap.get(key) != null) ? downloadMap.get(key) : 0, totalDownloads.getCounts());
					innerValue += innerValueMap.get(innerKeyList.get(0)) * factor_i * factor_j;
					// innerValue += 0;
				} else {
					for (int i = 0; i < innerKeyList.size(); i++) {
						int key_i = innerKeyList.get(i);
						float u = innerValueMap.get(key_i);
						float factor_u = calculateDownloadNumbersFacor(
								(downloadMap.get(key_i) != null) ? downloadMap.get(key_i) : 0,
								totalDownloads.getCounts());
						for (int j = i + 1; j < innerKeyList.size(); j++) {
							int key_j = innerKeyList.get(j);
							float v = innerValueMap.get(key_j);
							float factor_v = calculateDownloadNumbersFacor(
									(downloadMap.get(key_j) != null) ? downloadMap.get(key_j) : 0,
									totalDownloads.getCounts());
							innerValue += NOR(u * factor_u, v * factor_v);
						}
					}
				}
				innerValueSize = innerValueMap.size();
			}

			float outerValeAverage = (outerValueSize != 0) ? (outerValue / outerValueSize) : 0;
			float innerValeAverage = (innerValueSize != 0) ? (innerValue / innerValueSize) : 0;

			returnMap.put(key, NOR(outerValeAverage, innerValeAverage));
		}
		refreshReturnMap(returnMap, outerValueKeyMap, innerValueKeyMap, scale_size);
		return returnMap;
	}

	/**
	 * @author lczgywzyy
	 * @param mWafMatrix
	 *            waf文件路径；
	 * @param downloadMap
	 *            应用下载量；
	 * @param totalDownloads
	 *            总下载量；
	 * @param categoryMap
	 *            应用类别；
	 * @param factorMatrix
	 *            类别因子矩阵；
	 * @param scale_size
	 *            聚合节点规模；
	 * @param tag
	 *            分支标签。
	 * 
	 * @since NOR(Average(SUM(NOR(inner_i * factor_i, inner_j * factor_j) *
	 *        category_factor_ij)), Average(SUM(NOR(outer_i * factor_i, outer_j
	 *        * factor_j) * category_factor_ij)))
	 */
	@SuppressWarnings("rawtypes")
	public Map<Integer, Float> calculateWafValues5(String mWafMatrix, HashMap<Integer, Integer> downloadMap,
			TotalDownloads totalDownloads, HashMap<Integer, Integer> categoryMap, FactorUtils factorMatrix,
			int scale_size) {
		Map<Integer, Float> returnMap = new HashMap<Integer, Float>();
		Map<Integer, Map<Integer, Float>> outerMap = new HashMap<Integer, Map<Integer, Float>>();
		Map<Integer, Map<Integer, Float>> innerMap = new HashMap<Integer, Map<Integer, Float>>();
		Map<Integer, ArrayList<Integer>> outerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();
		Map<Integer, ArrayList<Integer>> innerValueKeyMap = new HashMap<Integer, ArrayList<Integer>>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(mWafMatrix)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith("row_size") && !line.startsWith("<row_index>") && line.contains("->")) {
					line = line.trim();
					int outerKey = Integer.parseInt(line.split("->")[0].trim());
					if (outerMap.get(outerKey) == null || outerMap.get(outerKey).isEmpty()) {
						// ArrayList<Float> tmplist = new ArrayList<Float>();
						// Map<Integer, Float> tmpMap = new HashMap<Integer,
						// Float>();
						outerMap.put(outerKey, new HashMap<Integer, Float>());
						outerValueKeyMap.put(outerKey, new ArrayList<Integer>());
					}
					if (returnMap.get(outerKey) == null) {
						Float tmp = 0.0f;
						returnMap.put(outerKey, tmp);
					}
					String tmpStr = line.split("->")[1].trim();
					while (tmpStr.contains("(") && tmpStr.contains(":") && tmpStr.contains(")")) {
						int innerKey = Integer
								.parseInt(tmpStr.substring(tmpStr.indexOf("(") + 1, tmpStr.indexOf(":")).trim());
						if (innerMap.get(innerKey) == null || innerMap.get(innerKey).isEmpty()) {
							// ArrayList<Float> tmplist = new
							// ArrayList<Float>();
							// Map<Integer, Float> tmpMap = new HashMap<Integer,
							// Float>();
							innerMap.put(innerKey, new HashMap<Integer, Float>());
							innerValueKeyMap.put(innerKey, new ArrayList<Integer>());
						}
						if (returnMap.get(innerKey) == null) {
							Float tmp = 0.0f;
							returnMap.put(innerKey, tmp);
						}
						float value = Float
								.parseFloat(tmpStr.substring(tmpStr.indexOf(":") + 1, tmpStr.indexOf(")")).trim());
						// outerMap.get(outerKey).add(value);
						// innerMap.get(innerKey).add(value);
						outerMap.get(outerKey).put(innerKey, value);
						outerValueKeyMap.get(outerKey).add(innerKey);
						innerMap.get(innerKey).put(outerKey, value);
						innerValueKeyMap.get(innerKey).add(outerKey);
						tmpStr = tmpStr.substring(tmpStr.indexOf(")") + 1);
					}
				}
			}
		} catch (FileNotFoundException fnfe) {
			fnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();

			Map<Integer, Float> outerValueMap = outerMap.get(key);
			ArrayList<Integer> outerKeyList = outerValueKeyMap.get(key);
			Map<Integer, Float> innerValueMap = innerMap.get(key);
			ArrayList<Integer> innerKeyList = innerValueKeyMap.get(key);

			float outerValue = 0.0f;
			int outerValueSize = 0;
			float innerValue = 0.0f;
			int innerValueSize = 0;

			boolean singular = false;
			if (outerKeyList != null && innerKeyList != null && !outerKeyList.isEmpty() && !innerKeyList.isEmpty()) {
				if (outerKeyList.size() == 1 && innerKeyList.size() == 1) {
					singular = (outerKeyList.get(0).equals(innerKeyList.get(0))) ? true : false;
				}
			}

			if (outerValueMap != null && !outerValueMap.isEmpty()) {
				if (outerValueMap.size() == 1) {
					if (singular) {
						outerValue += 0;
					} else {
						float factor_i = calculateDownloadNumbersFacor(
								(downloadMap.get(key) != null) ? downloadMap.get(key) : 0, totalDownloads.getCounts());
						float factor_j = calculateDownloadNumbersFacor((downloadMap.get(outerKeyList.get(0)) != null)
								? downloadMap.get(outerKeyList.get(0)) : 0, totalDownloads.getCounts());
						outerValue += outerValueMap.get(outerKeyList.get(0)) * factor_i * factor_j
								* factorMatrix.getFactor(categoryMap.get(key), categoryMap.get(outerKeyList.get(0)));
					}
				} else {
					for (int i = 0; i < outerKeyList.size(); i++) {
						int key_i = outerKeyList.get(i);
						float u = outerValueMap.get(key_i);
						float factor_u = calculateDownloadNumbersFacor(
								(downloadMap.get(key_i) != null) ? downloadMap.get(key_i) : 0,
								totalDownloads.getCounts());
						for (int j = i + 1; j < outerKeyList.size(); j++) {
							int key_j = outerKeyList.get(j);
							float v = outerValueMap.get(key_j);
							float factor_v = calculateDownloadNumbersFacor(
									(downloadMap.get(key_j) != null) ? downloadMap.get(key_j) : 0,
									totalDownloads.getCounts());
							outerValue += NOR(
									u * factor_u * factorMatrix.getFactor(categoryMap.get(key), categoryMap.get(key_i)),
									v * factor_v
											* factorMatrix.getFactor(categoryMap.get(key), categoryMap.get(key_j)));
						}
					}
				}
				outerValueSize = outerValueMap.size();
			}

			if (innerValueMap != null && !innerValueMap.isEmpty()) {
				if (innerValueMap.size() == 1) {
					if (singular) {
						innerValue += 0;
					} else {
						float factor_i = calculateDownloadNumbersFacor((downloadMap.get(innerKeyList.get(0)) != null)
								? downloadMap.get(innerKeyList.get(0)) : 0, totalDownloads.getCounts());
						float factor_j = calculateDownloadNumbersFacor(
								(downloadMap.get(key) != null) ? downloadMap.get(key) : 0, totalDownloads.getCounts());
						innerValue += innerValueMap.get(innerKeyList.get(0)) * factor_i * factor_j
								* factorMatrix.getFactor(categoryMap.get(innerKeyList.get(0)), categoryMap.get(key));
					}
				} else {
					for (int i = 0; i < innerKeyList.size(); i++) {
						int key_i = innerKeyList.get(i);
						float u = innerValueMap.get(key_i);
						float factor_u = calculateDownloadNumbersFacor(
								(downloadMap.get(key_i) != null) ? downloadMap.get(key_i) : 0,
								totalDownloads.getCounts());
						for (int j = i + 1; j < innerKeyList.size(); j++) {
							int key_j = innerKeyList.get(j);
							float v = innerValueMap.get(key_j);
							float factor_v = calculateDownloadNumbersFacor(
									(downloadMap.get(key_j) != null) ? downloadMap.get(key_j) : 0,
									totalDownloads.getCounts());
							innerValue += NOR(
									u * factor_u * factorMatrix.getFactor(categoryMap.get(key_i), categoryMap.get(key)),
									v * factor_v
											* factorMatrix.getFactor(categoryMap.get(key_j), categoryMap.get(key)));
						}
					}
				}
				innerValueSize = innerValueMap.size();
			}

			float outerValeAverage = (outerValueSize != 0) ? (outerValue / outerValueSize) : 0;
			float innerValeAverage = (innerValueSize != 0) ? (innerValue / innerValueSize) : 0;

			returnMap.put(key, NOR(outerValeAverage, innerValeAverage));
		}
		this.outerValueKeyMap = outerValueKeyMap;
		this.innerValueKeyMap = innerValueKeyMap;
		refreshReturnMap(returnMap, outerValueKeyMap, innerValueKeyMap, scale_size);
		return returnMap;
	}

	public void writeTermid_List_WithStartAndEnd(List<Aliases> aliases, String filePath) {
		HashSet<Integer> startNodeIDSet = new HashSet<Integer>();
		HashSet<Integer> endNodeIDSet = new HashSet<Integer>();
		HashSet<Integer> allNodeIDSet = new HashSet<Integer>();
		HashSet<String> allPathSet = new HashSet<String>();
		CRSMetrics.getInstance().fetchSourceNode(aliases, allNodeIDSet, startNodeIDSet, endNodeIDSet);
		LGraph lg = new LGraph(aliases, allNodeIDSet, 0);
		BufferedWriter bufWriter = null;
		try {
			bufWriter = new BufferedWriter(new FileWriter(filePath));
			for (int i : startNodeIDSet) {
				for (int j : endNodeIDSet) {
					LAF operation = new LAF(lg, i, j);
					boolean rtnValue = operation.getResult();
					if (rtnValue) {
						allPathSet.add(operation.getResultText());
						logger.debug(operation.getResultText());
					}
				}
			}
			for (String s : allPathSet) {
				bufWriter.write(s);
			}
			/* 多线程代码，处理不当，效果并不好。 */
			// int cnt = 16;
			// ArrayList<HashSet<Integer>> tmpSetList = new
			// ArrayList<HashSet<Integer>>();
			// HashSet<Integer> tmpSet = new HashSet<Integer>();
			// for (int i : startNodeIDSet) {
			// tmpSet.add(i);
			// if (tmpSet.size() > startNodeIDSet.size() / (cnt - 1)) {
			// tmpSetList.add(tmpSet);
			// tmpSet = new HashSet<Integer>();
			// }
			// }
			// tmpSetList.add(tmpSet);
			//
			// ConcurrentLinkedQueue<String> queue = new
			// ConcurrentLinkedQueue<String>();
			// ExecutorService executor = Executors.newFixedThreadPool(cnt + 1);
			// int i = 1;
			// for (HashSet<Integer> ts : tmpSetList) {
			// LGraph tmpLg = (LGraph) lg.clone();
			// PathComputingThread worker = new PathComputingThread(queue,
			// tmpLg, ts, endNodeIDSet);
			// executor.execute(worker);
			// logger.info("Thread " + i);
			// i++;
			// }
			// PathWritingThread monitor = new PathWritingThread(bufWriter,
			// queue);
			// new Thread(monitor).start();
			// executor.shutdown();
			// while (!executor.isTerminated()) {
			// try {
			// Thread.sleep(10000);
			// logger.info("Thread sleep");
			// } catch (InterruptedException e) {
			// e.printStackTrace();
			// }
			// }
			// monitor.setFlag(false);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void writeTermid_List(List<Aliases> aliases, String filePath) {
		HashSet<Integer> startNodeIDSet = new HashSet<Integer>();
		HashSet<Integer> endNodeIDSet = new HashSet<Integer>();
		HashSet<Integer> allNodeIDSet = new HashSet<Integer>();
		CRSMetrics.getInstance().fetchSourceNode(aliases, allNodeIDSet, startNodeIDSet, endNodeIDSet);
		HashSet<String> tmpSet = calculatePaths(startNodeIDSet, endNodeIDSet);
		BufferedWriter bufWriter = null;
		try {
			bufWriter = new BufferedWriter(new FileWriter(filePath));
			for (String str : tmpSet) {
				bufWriter.write(str + " -1\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("resource")
	public void writeGTermid_List(String scriptPath) {
		try {
			// ArrayList<String> commandAndParameters = new
			// ArrayList<String>(Arrays.asList("python", scriptPath));
			// File dir = new File("/usr/bin");
			// ProcessBuilder builder = new ProcessBuilder();
			// builder.redirectErrorStream(true); // This is the important part
			// builder.command(commandAndParameters);
			// builder.directory(dir);
			// Process proc = builder.start();
			// proc.getInputStream().close();
			// proc.getOutputStream().close();
			// proc.getErrorStream().close();
			// proc.waitFor();
			PythonInterpreter interpreter = new PythonInterpreter();
			InputStream filepy = new FileInputStream(scriptPath);
			interpreter.execfile(filepy); /// 执行python py文件
			filepy.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void writeBriefTermid_List(List<Aliases> aliases, String filePath) {
		BufferedWriter bufWriter = null;
		try {
			bufWriter = new BufferedWriter(new FileWriter(filePath));
			for (int i = 0; i < aliases.size(); i++) {
				Aliases a = aliases.get(i);
				String keyS = "" + a.getSid();
				String keyT = "" + a.getTid();
				if (!keyS.equals(keyT)) {
					bufWriter.write(keyS + " " + keyT + " -1\n");
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private float NOR(float a, float b) {
		float value = (a == 0 || b == 0) ? 0 : ((a >= b) ? (b / a) : (a / b));
		return value;
	}

	@SuppressWarnings("rawtypes")
	private void refreshReturnMap(Map<Integer, Float> returnMap, Map<Integer, ArrayList<Integer>> outerValueKeyMap,
			Map<Integer, ArrayList<Integer>> innerValueKeyMap, int scale_size) {
		ArrayList<Integer> returnKeyList = new ArrayList<Integer>();
		HashSet<Integer> tmpSet = new HashSet<Integer>();
		/*
		 * 测试遍历结果是否正确。
		 */
		ArrayList<Integer> test1 = new ArrayList<Integer>();
		HashSet<Integer> test2 = new HashSet<Integer>();

		Iterator iter = returnMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			tmpSet.add(key);
		}
		returnKeyList.addAll(tmpSet);

		while (returnKeyList.size() != 0) {
			tmpSet.clear();
			int targetNodeId = returnKeyList.get(0);
			tmpSet.add(targetNodeId);
			calculateNodeGroup(targetNodeId, tmpSet, outerValueKeyMap, innerValueKeyMap);
			returnKeyList.removeAll(tmpSet);
			if (tmpSet.size() < scale_size) {
				for (int id : tmpSet) {
					returnMap.put(id, -1.0f);
				}
			} else {
				String temp = "";
				for (int id : tmpSet) {
					temp += id + " ";
					test1.add(id);
					test2.add(id);
				}
				logger.debug(temp);
			}
		}
		/*
		 * 测试遍历结果是否正确。经测试，Test1和Test2的size相同，说明遍历的时候不存在重复遍历的点，不会有点既在其他点的遍历路径中、
		 * 又重复作为起始点计算。
		 */
		logger.debug("Test1.size = " + test1.size());
		logger.debug("Test2.size = " + test2.size());
	}

	private void calculateNodeGroup(int nodeId, HashSet<Integer> tmpSet,
			Map<Integer, ArrayList<Integer>> outerValueKeyMap, Map<Integer, ArrayList<Integer>> innerValueKeyMap) {
		ArrayList<Integer> tmpOuterList = outerValueKeyMap.get(nodeId);
		ArrayList<Integer> tmpInnerList = innerValueKeyMap.get(nodeId);
		if (tmpOuterList != null) {
			for (int i = 0; i < tmpOuterList.size(); i++) {
				if (!tmpSet.contains(tmpOuterList.get(i))) {
					tmpSet.add(tmpOuterList.get(i));
					calculateNodeGroup(tmpOuterList.get(i), tmpSet, outerValueKeyMap, innerValueKeyMap);
				}
			}
		}
		if (tmpInnerList != null) {
			for (int i = 0; i < tmpInnerList.size(); i++) {
				if (!tmpSet.contains(tmpInnerList.get(i))) {
					tmpSet.add(tmpInnerList.get(i));
					calculateNodeGroup(tmpInnerList.get(i), tmpSet, outerValueKeyMap, innerValueKeyMap);
				}
			}
		}
	}

	private float calculateDownloadNumbersFacor(int i, BigInteger bigInteger) {
		float returnValue = bigInteger.longValue();
		// returnValue = (float) Math.sqrt((BigInteger.valueOf((long)
		// 1.0).divide(BigInteger.valueOf((long)
		// 1.0).subtract(BigInteger.valueOf(i).divide(bigInteger)))).floatValue());
		returnValue = (float) Math.sqrt(1 / (1 - i / returnValue));
		return returnValue;
	}

	// TODO
	@SuppressWarnings("rawtypes")
	public List<Aliases> ReinitialAliases(List<Aliases> aliases, Map<Integer, Float> tValueMap) {
		List<Aliases> returnAliases = new ArrayList<Aliases>();
		HashSet<Integer> tValueSet = new HashSet<Integer>();
		Iterator iter = tValueMap.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			float value = (float) entry.getValue();
			if (value != -1) {
				tValueSet.add((int) entry.getKey());
			}
		}
		for (Aliases aliase : aliases) {
			if (tValueSet.contains(aliase.getSid()) && tValueSet.contains(aliase.getTid())) {
				returnAliases.add(aliase);
			}
		}
		return returnAliases;
	}

	private HashSet<String> calculatePaths(HashSet<Integer> startNodeIDSet, HashSet<Integer> endNodeIDSet) {
		HashSet<String> tmpSet = new HashSet<String>();
		HashSet<String> returnSet = new HashSet<String>();

		String path = "";
		for (int start : startNodeIDSet) {
			path = " " + start + " ";
			ArrayList<Integer> tmpOuterList = outerValueKeyMap.get(start);
			for (int target : tmpOuterList) {
				path += target + " ";
				calculatePath(tmpSet, path, target);
			}
		}
		for (String str : tmpSet) {
			int endID = Integer.parseInt(str.substring(str.lastIndexOf(" ")).trim());
			if (endNodeIDSet.contains(endID)) {
				returnSet.add(str);
			}
		}
		return returnSet;
	}

	private void calculatePath(HashSet<String> tmpSet, String path, int nodeID) {
		ArrayList<Integer> tmpOuterList = outerValueKeyMap.get(nodeID);
		if (tmpOuterList != null) {
			for (int i = 0; i < tmpOuterList.size(); i++) {
				int target = tmpOuterList.get(i);
				if (path.contains(" " + target + " ")) {
					continue;
				}
				path += target + " ";
				calculatePath(tmpSet, path, target);
			}
		} else {
			tmpSet.add(path.trim());
		}
	}
}
